#pragma once
#include<iostream>
#include<assert.h>
#include<initializer_list>
using namespace std;
namespace Mango
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;

        //默认成员函数
        vector()
            :_start(nullptr),_finish(nullptr),_endofstorage(nullptr)
        {}
        vector(size_t n, const T& val)
            :_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            reserve(n);
            for (int i = 0; i < n; i++)
            {
                push_back(val);
            }
        }
        vector(int n, const T& val)
            :_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            reserve(n);
            for (int i = 0; i < n; i++)
            {
                push_back(val);
            }
        }
        vector(long n, const T& val)
            :_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            reserve(n);
            for (int i = 0; i < n; i++)
            {
                push_back(val);
            }
        }
        
        vector(const initializer_list<T>& il)
            :_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            for (auto& x : il)
            {
                push_back(x);
            }
        }
        template<class InputIterator>
        vector(InputIterator first, InputIterator last)
            :_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            while (first != last)
            {
                push_back(*first);
                first++;
            }
        }
        vector(const vector<T>& v) 
            :_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            _start = new T[v.capacity()];
            _finish = _start + v.size();
            _endofstorage = _start + v.capacity();
            for (int i = 0; i < v.size(); i++)
            {
                _start[i] = v[i];
            }
        }
        void swap(vector<T>& v)
        {
            std::swap(v._start,_start);
            std::swap(v._finish,_finish);
            std::swap(v._endofstorage,_endofstorage);
        }
        //拷贝构造函数的参数必须是引用，因为传值传参本质是拷贝构造
        // 如果拷贝构造函数的参数是值传参，那么就会陷入死递归
        ////现代写法1：
#if 0
        vector(const vector<T>& v)
            :_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            for (auto& x : v)
            {
                push_back(x);
            }
        }
#endif
#if 0
        //现代写法2:
        vector(const vector<T>& v)
            :_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            vector<T> tmp(v.begin(), v.end());
            swap(tmp);
        }
#endif
        //传统写法
        vector<T>& operator=(const vector<T>& v)
        {
            if (this != &v)
            {
                delete[] _start;
                _start = new T[v.capacity()];
                _finish = _start;
                //注意这里要让_finish的指向新空间
                for (auto& x : v)
                {
                    push_back(x);
                }
                _endofstorage = _start + capacity();
            }
            return *this;
        }
#if 0
        //现代写法
        vector<T>& operator=(vector<T> v)
        {
            swap(v);//如果是v1 = v1 这种情况，虽然内容没有发生改变，但是v1空间的地址变了
            return *this;
        }
#endif
        ~vector()
        {
            if (_start != nullptr)
            {
                delete[] _start; //注意：这里要使用的是delete[] 否则会崩溃！
            }
            _start = _finish = _endofstorage = nullptr;
        }

        //迭代器相关函数
        iterator begin()
        {
            return _start;
        }
        iterator end()
        {
            return _finish;
        }
        const_iterator begin()const
        {
            return _start;
        }
        const_iterator end()const
        {
            return _finish;
        }

        //容量和大小相关函数
        size_t size()const
        {
            return _finish - _start;
        }
        size_t capacity()const
        {
            return _endofstorage - _start;
        }
        void reserve(size_t n)
        {
            if (n > capacity())
            {
                T* tmp = new T[n];
                size_t sz = size();//为了后序更改finish的位置
                if (_start != nullptr)
                {
                    for (int i = 0; i < sz; i++)
                    {
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }
                _start = tmp;
                _finish = _start + sz;
                _endofstorage = _start + n;
            }
        }
        void resize(size_t n, const T& val = T())
        {
            if (n < size())
            {
                _finish = _start + n;
            }
            else
            {
                if (n > capacity()) //判断是否需要扩容
                {
                    reserve(n);
                }
                //插入元素-直到size为n
                while (n != size())  //或者写成:_finish != _start + n
                {
                    *_finish = val;
                    _finish++;
                }
            }
        }
        bool empty() const
        {
            return size() == 0;
        }

        //修改容器内容相关函数
        void push_back(const T& x)
        {
            if (_finish == _endofstorage) //容量满了
            {
                int cap = capacity();
                reserve(cap == 0 ? 4 : cap * 2);
            }
            *_finish = x;
            _finish++;
        }
        void pop_back()
        {
            assert(!empty());
            _finish--;
        }
        void insert(iterator pos, const T& x)
        {
            //保证pos位置的合法性
            assert(pos >= begin());
            assert(pos <= end());
            if (_finish == _endofstorage)
            {
                //注意：这里需要保存pos与_start的距离
                //因为增容之后,_start已经指向新空间了，pos属于非法访问
                int len = pos - begin();
                int cap = capacity();
                reserve(cap == 0 ? 4 : cap * 2);
                pos = _start + len;//重新更新pos位置
            }
            //把值往后移动
            iterator end = _finish - 1;
            while (end >= pos)
            {
                *(end + 1) = *end;
                end--;
            }
            *pos = x;
            _finish++;
        }

        iterator erase(iterator pos)
        {
            assert(pos >= begin());
            assert(pos < end());
            iterator cur = pos + 1;
            while (cur != _finish)
            {
                *(cur - 1) = *cur;
                cur++;
            }
            _finish--;
            return pos;
        }
        

        //访问容器相关函数
        T& operator[](size_t i)
        {
            assert(i < size());
            return _start[i];
        }
        const T& operator[](size_t i)const
        {
            assert(i < size());
            return _start[i];
        }

    private:
        T* _start;        //指向容器的头
        T* _finish;       //指向有效数据的尾
        T* _endofstorage; //指向容器的尾
    };
}
